/******************************************************************************
 cnome: A C++ source "genes" discover. :-)

 See more details at:

   http://www.codeplex.com/cnome

 The original author site is at: http://www.alemosbarbosa.com/

 Copyright (c) 2008-2010 Alexandre Lemos Barbosa.
 Distributed under the MIT License. (See accompanying file LICENSE-MIT.txt 
 or at http://www.codeplex.com/cnome/license)
 ******************************************************************************/

#ifndef SYMBOL_H
#define SYMBOL_H

#include <boost/spirit/include/classic_core.hpp>
#include <boost/spirit/include/classic_symbols.hpp>
#include <iostream>
#include <list>
#include <string>

#include "identifier_zone.h"
#include "iterator.h"
#include "typedefs.h"
#include "parameter.h"
#include "tst_avl.h"

namespace cnome {
class symbol : public token_t {
public:
    typedef	std::list<symbolPtr> innersT;
    typedef	innersT::iterator it_innersT;
    typedef	innersT::const_iterator const_it_innersT;
	typedef std::map<iterator, symbolPtr> referencesT;

    enum symbolType
    {
        unknown,
        internal, // for internal use by grammar engine
        keyword,  // char, int, long, float, double, boolean
        member,
        method,
        enumerator,
        enun_name,
        parameter,
        template_parameter,
        typedefname,
        point_to_function,
        template_variable,
        other,
        last_symbolType 
    };

    enum identifierType
    {
        NONE,
        T_CLASS_NAME,
        T_ENUM_NAME,
        T_ORIGINAL_NAMESPACE_NAME,
        T_TEMPLATE_NAME,
        T_NAMESPACE_ALIAS,
        T_TYPEDEF_NAME,
        T_TEMPLATE_PARAMETER,
        T_TEMPLATE_VARIABLE,
		last_identifierType
    };

    static const char* strSymbolType[last_symbolType];

    enum statusDD  // Status of Data Declaration/Definition
    {
        unknow,
        declared,
        defined,
        last_statusDD 
    };
    static const char* strStatusDD[last_statusDD];

    // TODO: Review constructors in order to analyze the posibility of ones having the same parameters of token_t
    symbol();
    symbol(boost::wave::token_id argTkId, std::size_t a_pos);
    symbol(const token_t& argTk, symbolType s, std::size_t a_pos);
    symbol(const symbol& s);
    virtual ~symbol();

    void set_token(const token_t& tk)
    {
        *static_cast<token_t*>(this)=tk;
        update_str();
    }
    symbolType get_symbol_type() const { return m_sblTyp; }
    void  set_symbol_type(symbolType s) {
        m_sblTyp=s;
        update_str();
    }
    statusDD get_symbol_status() const { return m_stt; }
    void  set_symbol_status(statusDD s) { m_stt=s; }
    const symbolPtr get_type_symbol() const { return m_typeTk; }
    void  set_type_symbol(const symbolPtr s);
    const symbolPtr get_scope() const { return m_scope; }
    void  set_scope(const symbolPtr s);
    const adornersT& get_adorners() const { return m_adorners; }
    void  set_adorners(const adornersT& a) { m_adorners=a; }
    const char* to_str(void) const { return m_str; }
    symbol& operator=(const symbol&);
    symbol& operator*();
    symbolPtr add(symbolPtr);
    const symbolPtr  add(const symbol&);
    const innersT& get_inners() const { return m_inners; }
	innersT& get_inners() { return const_cast<innersT&>(const_cast<const symbol&>(*this).get_inners()); }
    void set_inners(const innersT& inners) { m_inners=inners; }
    int  get_parameter_position() { return m_paramPos; }
    void set_parameter_position(int p) { m_paramPos = p; }
    identifierType get_identifier_type() const { return m_identifierType; }
    void set_identifier_type(identifierType id) { m_identifierType = id; }
    const std::size_t get_cnome_position() { return m_pos; }
    void set_cnome_position(std::size_t a) { m_pos = a; }
    std::set<iterator>& get_definitions() { return m_definitions; }
    std::set<iterator>& get_declarations() { return m_declarations; }
    referencesT& get_references() { return m_references; }
    referencesT const& get_references() const { return m_references; }

protected:
    virtual void update_str(); 
	virtual std::ostream& summary(std::ostream&) const;

private:
    std::set<iterator> m_definitions;  // It is valid only one definition
    std::set<iterator> m_declarations;
    referencesT m_references;
    symbolType m_sblTyp;
    symbolPtr m_typeTk;    // Pointer to type token if any
    symbolPtr m_scope;     // Pointer to enclosing scope if any
    statusDD   m_stt;
    char*      m_str;                   // Contains the entire scope of symbol
    adornersT  m_adorners;
    innersT    m_inners;               // Used by typedef, class methods and fields and method parameters
    innersT    m_inrsCreated;          // Symbols created internally that must be deleted in destructor
    int        m_paramPos;               // Position of parameter in the parameter list.
    identifierType m_identifierType;
    std::size_t m_pos;

	friend std::ostream& operator<<(std::ostream&, symbol const&);
};

class mmbORprm: public symbol  // Member or parameter item
{
    mmbORprm(): symbol() {}
    mmbORprm(boost::wave::token_id argTkId, std::size_t a_pos): symbol(argTkId, a_pos) {}
    mmbORprm(const token_t& argTk, symbolType s=other, std::size_t a_pos = 0) : symbol(argTk, s, a_pos) {}
    bool getHasDefault() { return hasDefault; }
    void setHasDefault(bool d) { hasDefault=d; }
private:
    bool hasDefault;
    symbol defaultValue;
};

class classSbl: public symbol
{
    classSbl(): symbol() {}
    classSbl(boost::wave::token_id argTkId, std::size_t a_pos): symbol(argTkId, a_pos) {}
    classSbl(const token_t& argTk, symbolType s=other, std::size_t a_pos=0) : symbol(argTk, s, a_pos) {}
private:
    std::list<mmbORprm*> members;
    // Members bellow is used by type symbol
    bool       isRef;                   
    bool       isPtr;
    bool       isConst;
};

class methodSbl: public symbol
{
    methodSbl(): symbol() {}
    methodSbl(boost::wave::token_id argTkId, std::size_t a_pos): symbol(argTkId, a_pos) {}
    methodSbl(const token_t& argTk, symbolType s=other, std::size_t a_pos=0) : symbol(argTk, s, a_pos) {}
private:
    std::list<mmbORprm*> parameters;
};

const unsigned long UNKNOWNANNOTATION     = 0;
const unsigned long IDENTIFIERANNOTATION  = 1;
const unsigned long PARAMETERANNOTATION   = 2;
const unsigned long PARENTHESISANNOTATION = 3;

class identifier_annotation : public token_annotation
{
public:
	identifier_annotation(symbolPtr const &symbol_item_ptr_, symbol::identifierType id_type_, identifier_zone::eIdentifierZone id_zone_ = identifier_zone::var_use) 
        : symbol_item_ptr(symbol_item_ptr_), id_type(id_type_), id_zone(id_zone_) {}
    virtual tag_type get_tag() const { return IDENTIFIERANNOTATION; }

    symbolPtr& get_symbol_item_ptr() { return symbol_item_ptr; }
    void set_symbol_item_ptr(symbolPtr const& symbol_item_ptr_)
    { symbol_item_ptr = symbol_item_ptr_; }
    symbol::identifierType get_id_type() const { return id_type; }
    void set_id_type(symbol::identifierType id_type_) { id_type = id_type_; }
	identifier_zone::eIdentifierZone get_id_zone() const { return id_zone; }
	void set_id_zone(identifier_zone::eIdentifierZone id_zone_) { id_zone = id_zone_; }

private:
    symbolPtr symbol_item_ptr;
    symbol::identifierType id_type;
	identifier_zone::eIdentifierZone id_zone;
};

class parameter_annotation : public identifier_annotation
{
public:
    parameter_annotation(symbolPtr const &symbol_item_ptr_, symbol::identifierType id_type_,
        const parameter_scope::position_type& index_, eParameterType parameter_type_ = method_parameter): 
        identifier_annotation(symbol_item_ptr_, id_type_), 
        index(index_), parameter_type(parameter_type_) {}
    virtual tag_type get_tag() const { return PARAMETERANNOTATION; }

    int get_level() const { return static_cast<int>(index.size()) - 1; }
    const parameter_scope::position_type& get_index() const { return index; }
    void set_index(const parameter_scope::position_type& index_) { index = index_; }
    eParameterType get_parameter_type() { return parameter_type; }
    void set_parameter_type(eParameterType parameter_type_) { parameter_type = parameter_type_; }
private:
    parameter_scope::position_type index;
    eParameterType parameter_type;
};

class parenthesis_annotation : public token_annotation {
public:
    enum eparenthesis_type {
        unknown_type,
        method_type,
        ptr_to_fct_type
    };

    parenthesis_annotation(int level_, eparenthesis_type parenthesis_type_) : level(level_), parenthesis_type(parenthesis_type_) {}
    virtual tag_type get_tag() const { return PARENTHESISANNOTATION; }

    int get_level() const { return level; }
    void set_level(int level_) { level = level_; }

    eparenthesis_type get_parenthesis_type() { return parenthesis_type; }
    void set_parenthesis_type(eparenthesis_type parenthesis_type_) { parenthesis_type = parenthesis_type_; }
private:
    int level;
    eparenthesis_type parenthesis_type;
};

extern cnome::tst_avl::tst_avl<std::string, symbolPtr> cnome_symbols;
extern symbol const smb_FIRST_TOKEN;

std::ostream& operator<<(std::ostream&, symbol const&);
}  // namespace cnome

#endif // SYMBOL_H
